/*
 *	Stdio sscanf
 */

#include	<stdio.h>
#include	<string.h>
#include	<stdarg.h>

#include "s_scanf.h"
//#include "utils.h"

/*
 *	_doscan - implement scanf, fscanf, sscanf
 */

//#include	<stdio.h>
/* #include 	<ctype.h> */
/* #include	<stdlib.h> */
//#include	<stdarg.h>
/* #include	<conio.h> */
/* #include	<string.h> */
/* #include	<hitech.h> */

/* #if	defined(i8051) && defined(SMALL_MODEL) */
/* #define	STATIC	static idata */
/* #define	EXTERN	extern idata */
/* #else */
/* #define	STATIC	static */
/* #define	EXTERN	extern */
/* #endif */

/* STATIC const char *	ptr; */
/* EXTERN char		_scanf_buf_[]; */
/* STATIC uchar		flag; */

/* #if	defined(i8086) */
/* STATIC unsigned int	boffs; */
/* #else */
/* STATIC uchar		boffs; */
/* #endif */

char	_scanf_buf_[64];
static const char *	ptr;
static unsigned int	flag;
unsigned int boffs;

int isupper( int c )
{
	return ( c >='A' && c <= 'Z' );
}

int isalpha( int c )
{
	return ( (c >= 'a' && c <= 'z')  || isupper(c) );
}

int isspace( int c )
{
	return ( c == ' ' || (c <= 015 && c >= 011) );
}

int isdigit( int c )
{
	return ( c >= '0' && c <= '9' );
}

int tolower( int c )
{
	if( c >= 'A' && c <= 'Z' )
	{
		c |= ('a' - 'A');
	}

	return c;
}



static void ungetchl( void )
{
	if(ptr)
		ptr--;
	
	if(!flag)
		boffs = ptr-_scanf_buf_;
}

static unsigned char getchl( void )
{
	unsigned char c;

	if( flag )
	{
		if(ptr && *ptr)
		{
			return *ptr++;
		}
		else
		{
			return 0;
		}
	}

	if( !ptr || *ptr == 0 ) 
	{
		//cgets(_scanf_buf_);??????????????????????????????????
		strcat(_scanf_buf_, "\n");
		ptr = _scanf_buf_;
	}

	c = *ptr++;
	boffs = ptr-_scanf_buf_;

	return c;
}

static int range(unsigned char c, unsigned char base)
{
	if( isdigit(c) )
	{
		c -= '0';
	}
	else
	{
		if ( isupper(c) )
		{
			c = tolower(c) ;
		}

		if ( isalpha(c) )
		{
			c = c - 'a' + 10; //A41 61 - 41 - 0x20 32+10=42
 		}
		else
		{
			return -1;
		}
	}

	if ( c >= base )
	{
		return -1;
	}

	return c;
}


static void wspace ( void )
{
	unsigned char c;

	while(isspace(c = getchl()))
		continue;

	if(c != 0)
		ungetchl();
}

static int _doscan(const char * str, const char * fmt, va_list ap)
{
	int c, sign, base, n, noass,len;
	int	width ;
	char *sptr = NULL;
	unsigned int ch;
	long	val;
	
	int add_to_n; /* dima */

	if(str) 
	{
		flag = 1;
		ptr = str;
	} 
	else 
	{
		flag = 0;
		ptr = _scanf_buf_+boffs;
	}

	n = 0;

	while( (c = *fmt++) ) 
	{
		len = sizeof(int);
		
		if( isspace(c) ) 
		{
			wspace();
			continue;
		}

		if( c == '%' ) 
		{
			noass = 0;
			width = 0;
			add_to_n = 0;			  /* dima */
loop:
			switch(c = *fmt++) 
			{
				case '\0':
					return n;

				case '*':
					noass++;
					goto loop;

				case '.':			  /* dima */
					noass++;
					add_to_n++;
					goto loop;

				case 'l':
				case 'L':
					len = sizeof(long);
					goto loop;

				case 'h':
					len = sizeof(short);
					goto loop;

				case 'd':
				case 'u':
					base = 10;
					break;

				case 'o':
					base = 8;
					break;

				case 'X':
				case 'x':
					base = 16;
					break ;

				case 's':
					wspace();
					if ( !noass )
						sptr = va_arg(ap, char *);
					if ((ch = getchl()) == 0)
						return n ? n : EOF;
					while(ch && !isspace(ch)) 
					{
						if(ch == *fmt) 
						{
							fmt++;
							break;
						}

						if ( !noass ) 
							*sptr++ = ch;
						if(--width == 0)
							break;
						ch = getchl();
					}

					if(!noass) 
					{
						n++;
						*sptr = 0;
					}
					else
						if ( add_to_n )
						{
							n++;
						}

					continue;

				case 'c':
					if ( !noass ) 
					{
						n++;
						sptr = va_arg(ap, char *);
					}
					else
						if ( add_to_n )
						{
							n++;
						}

					do 
					{
						if ((ch = getchl()) == 0) 
							return n ? n : EOF;
						if ( !noass )
							*sptr++ = ch;
					} while(--width > 0);
					
					continue;
					
				default:
					if( isdigit(c) ) 
					{
						width = atoi(fmt-1);
						//width = StrToLong(fmt-1);

						while( isdigit(*fmt) )
							fmt++;

						goto loop;
					}

					if(c != (ch = getchl()))
					{
						if(ch == 0)
							return n ? n : EOF;
						else 
						{
							ungetchl();
							return n;
						}
					}
					continue;
			}

			wspace();
			val = 0;
			sign = 0;
			ch = getchl();

			if(ch == '-') 
			{
				sign++;
				ch = getchl();
			}

			if(ch == '+')
				ch = getchl();
			
			if(range(ch, base) == -1) 
			{
				if(ch != 0)
					ungetchl();
				return n;
			}

			do 
			{
				unsigned char x;

				x = range(ch, base);
				val = val * base + x;
			} while (( --width != 0 ) && ( range(ch = getchl(),base) != -1)) ;
			
			if (ch != 0 && range(ch,base) == -1)
				ungetchl();
			
			if(sign)
				val = -val;
			
			if ( !noass )  
			{
				n++;
				if(len == sizeof(long))
					*va_arg(ap, long *) = val;
				else if(len == sizeof(short))
					*va_arg(ap, short *) = val;
				else
					*va_arg(ap, int *) = val;
			}
			else
				if ( add_to_n )
				{
					n++;
				}

			continue;

		}
		else
		{ 
			if(c != (ch = getchl())) 
			{
				
				if(ch != 0) 
				{
					ungetchl();
					return n;
				} 
				else
					return n ? n : EOF;
			}
			
			if ( n == 0 && *fmt == 0 )
			{
				return ++n;	
			}
		}
	}

	return n;
}


int s_scanf(const char * str, const char * fmt, ...)
{
	va_list	ap;
	va_start(ap, fmt);

	return _doscan(str, fmt, ap);
}
